#ifndef ___fuse_open
#define ___fuse_open 1

#ifndef FUSE_USE_VERSION
#define FUSE_USE_VERSION 28
#endif

#include <stdio.h>
#include <stdlib.h>
#include "mtlib.c"
#include <fuse.h>
#include <fcntl.h>
#include <errno.h>
#include "logging.c"

struct datosAbrir {
    char * path;
    struct fuse_file_info * ptr;
    char estado;
};

//Prototipos
int fuse_open(const char *, struct fuse_file_info *);
void ___fuse_procesar_mensaje_open(unsigned char, mti_mensaje, struct datosAbrir *);

//ABRIR ARCHIVO
int fuse_open(const char * path, struct fuse_file_info * pNue) { // le paso un puntero una estructura que entre otros
//campos posee los flags que me indican si el archivo es de tipo lectura, escritura o ambos.

    int resultado;
    mti_mensaje datosMensaje;
    char modo;
    unsigned char centro_open = 0;
    unsigned int descriptorConexion;
    struct datosAbrir datos;

        datos.path = path;
        datos.ptr = pNue;
        datos.estado = 0;

        //puntero al campo flags de la estructura y me fijo si el archivo es solo lectura
        if ( (datos.ptr -> flags &3) == O_RDONLY ) { //pongo en cero 0 todos los bits menos los dos ultimos,, para poder comparar
            modo = 0;

        //puntero al campo flags de la estructura y me fijo si el archivo es solo lectura
        } else if ( (datos.ptr -> flags &3) == O_WRONLY ) {
            modo = 1;

        //idem arriba pero me fijo si es de escritura y lectura
        } else if ( (datos.ptr -> flags &3) == O_RDWR ) {
            modo = 2;
            

        //si no es ninguno de los anteriores devuelvo un error
        } else
            return -EACCES;

          while (!centro_open)
              centro_open = mtf_obtener_descriptor(1024);

          descriptorConexion = mtf_conectar(centro_open, MTP_INTERNO, centro_fat);

          if (descriptorConexion == 0) {
            mtf_liberar_descriptor(centro_open);
            return -EAGAIN;
          }

          resultado = mtf_enviar_mensaje(centro_open, descriptorConexion, MTE_ABRIR_ARCHIVO, (char *) datos.path, (int) modo);
          //envio un mensaje al sistema fat para abrir un determinado archivo,, por eso le paso su path y un modo para elegir
          // la operacion que deseo hacer sobre ese archivo (lectura, escritura, o ambos)

          if (resultado == 0) {
            mtf_desconectar(centro_open, descriptorConexion);
            mtf_liberar_descriptor(centro_open);
            return -EAGAIN;
          }

          while (!datos.estado) {

            if (!mtf_recibir_mensajes(centro_open)) continue;

            datosMensaje = mtf_siguiente_mensaje(centro_open);
            ___fuse_procesar_mensaje_open(centro_open, datosMensaje, &datos);
            mtf_descartar_mensaje(centro_open, datosMensaje.codigo);

          }

          mtf_desconectar(centro_open, descriptorConexion); //desconecto la conexion del centro de mensajes
          mtf_liberar_descriptor(centro_open); //libero centro de mensajes con sus datos y conexiones

          switch (datos.estado) {

          case 1:
                return -ENOENT; //path no exite
            case 2:
                return -EISDIR; //path es un directorio
            case 3:
                return -EAGAIN; //solo lectura, y se pidio escritura
            case 4:
                return -EACCES; //archivo abierto
            case 5:
                return -EAGAIN; //modo de apertura no es 0, 1 o 2
            case 6:
                return -EACCES; //se rompio todo
            default:
                return EXIT_SUCCESS;
          }
}

void ___fuse_procesar_mensaje_open(unsigned char centro_open, mti_mensaje datosMensaje, struct datosAbrir * datosApertura) {

    if (datosMensaje.categoria != MTA_MENSAJE) return;

      switch (datosMensaje.tipo) {

        case MTE_NULL:

          mtf_enviar_mensaje(centro_open, datosMensaje.remitente, MTR_NULL);

        break;

        case MTR_NULL: case MTQ_MENSAJE_NO_VALIDO:

        break;

        //MENSAJES PARA ABRIR ARCHIVO
        case MTR_ARCHIVO_ABIERTO:
        {
            long long descriptorArchivo;
            char * nombreArchivo = NULL;

                mtf_obtener_datos(centro_open, datosMensaje.codigo,(char **) &nombreArchivo,
                                    (long long *) &descriptorArchivo);

                log_registrar(descArch, "FUSE", LOG_INFO, "Descriptor archivo abierto %lld \n", descriptorArchivo );
                //lleno el campo file handle de la estructura con el descriptor obtenido y lo casteo al tipo correspondiente
                datosApertura -> ptr -> fh = (uint64_t) descriptorArchivo;
                free(nombreArchivo);
        }
        break;

        case MTR_NO_ABRIO_ARCHIVO:
        {
            char * nombreArchivo = NULL;
            char motivo;

                mtf_obtener_datos(centro_open, datosMensaje.codigo,(char **) &nombreArchivo, (char *) &motivo);

                datosApertura -> estado = motivo;
                log_registrar(descArch, "FUSE", LOG_WARN, "No se pudo abrir archivo %s \n", nombreArchivo);
                free(nombreArchivo);
        }
        break;

        default:

              mtf_enviar_mensaje(centro_open, datosMensaje.remitente, MTQ_MENSAJE_NO_VALIDO);

        break;

      }
}

#endif

